#include <stdlib.h>
#include <stdio.h>

#include "uart.h"
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "projdefs.h"
#include "semphr.h"
#include "drive.h"

/* include files. */
#include "lpc17xx_uart.h"
#include "vtUtilities.h"

#include "lpc17xx_libcfg_default.h"
#include "lpc17xx_pinsel.h"

/*
typedef struct __UARTStruct {
	uint8_t devNum;	  						// Number of the I2C peripheral (0,1,2 on the 1768)
	LPC_I2C_TypeDef *devAddr;	 			// Memory address of the I2C peripheral
	unsigned portBASE_TYPE taskPriority;   	// Priority of the I2C task
	xSemaphoreHandle binSemaphore;		   	// Semaphore used between I2C task and I2C interrupt handler
	xQueueHandle inQ;					   	// Queue used to send messages from other tasks to the I2C task
	xQueueHandle outQ;						// Queue used by the I2C task to send out results
	uint8_t recvBuf[UARTMLen];
	uint8_t recvCount;
} UARTStruct;

typedef struct __UARTMsg {
	uint8_t msgType; // A field you will likely use in your communications between processors (and for debugging)
	uint8_t slvAddr; // Address of the device to whom the message is being sent (or was sent)
	uint8_t	rxLen;	 // Length of the message you *expect* to receive (or, on the way back, the length that *was* received)
	uint8_t txLen;   // Length of the message you want to sent (or, on the way back, the length that *was* sent)
	uint8_t status;  // status of the completed operation -- I've not done anything much here, you probably should...
	uint8_t buf[UARTMLen]; // On the way in, message to be sent, on the way out, message received (if any)
} UARTMsg;
*/

#define baseStack 3
#if PRINTF_VERSION == 1
#define uartSTACK_SIZE		((baseStack+5)*configMINIMAL_STACK_SIZE)
#else
#define uartSTACK_SIZE		(baseStack*configMINIMAL_STACK_SIZE)
#endif

#define UARTQLen 10

#define uartTransferFailed -2
#define uartIntPriority 7

static UARTStruct* uart1static;

static portTASK_FUNCTION_PROTO( vUARTMonitorTask, pvParameters );

void sendUART(uint8_t* buffer, uint8_t buflen)
{
	UARTEnQ(uart1static,0,0,buflen,buffer,0);
}

int myUARTInit(UARTStruct *devPtr,uint8_t devNum,unsigned portBASE_TYPE taskPriority,uint32_t uartBaudRate)
{
	 uart1static = devPtr;
	 int retval = UARTInitSuccess;
	 LPC_UART_TypeDef* uartDevice;
	 if(devNum == 1)
	 	uartDevice = (LPC_UART_TypeDef*)LPC_UART1;
	 devPtr->devNum = devNum;
	 devPtr->taskPriority = taskPriority;
	 devPtr->devAddr = uartDevice;
	 devPtr->recvCount = 0;

	NVIC_SetPriority(UART1_IRQn,uartIntPriority);	
	NVIC_DisableIRQ(UART1_IRQn);

	 //Set up UART
     UART_CFG_Type uartConfig;
	 uartConfig.Baud_rate = uartBaudRate;
	 uartConfig.Parity = UART_PARITY_NONE;
	 uartConfig.Databits = UART_DATABIT_8;
	 uartConfig.Stopbits = UART_STOPBIT_1;
	 UART_Init(uartDevice, &uartConfig);
	 
	 //Enable TX FIFO
	 UART_FIFO_CFG_Type fifoconfig;
	 UART_FIFOConfigStructInit(&fifoconfig);
	 fifoconfig.FIFO_Level = UART_FIFO_TRGLEV0;
	 UART_FIFOConfig(uartDevice, &fifoconfig);
	 
	 //Enable TX 
	 UART_TxCmd(uartDevice, ENABLE);
	 
	 //Set up TX pin
	 PINSEL_CFG_Type pincfg;
	 pincfg.Portnum = PINSEL_PORT_0;
	 pincfg.Pinnum = PINSEL_PIN_15;
	 pincfg.Funcnum = PINSEL_FUNC_1;
	 pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
	 pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	 PINSEL_ConfigPin(&pincfg);

	 //Set up RX pin
	 pincfg.Portnum = PINSEL_PORT_0;
	 pincfg.Pinnum = PINSEL_PIN_16;
	 pincfg.Funcnum = PINSEL_FUNC_1;
	 pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
	 pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	 PINSEL_ConfigPin(&pincfg);
	 
	// Create semaphore to communicate with interrupt handler
	vSemaphoreCreateBinary(devPtr->binSemaphore);
	if (devPtr->binSemaphore == NULL) {
		return(UARTErrInit);
	}
	// Need to do an initial "take" on the semaphore to ensure that it is initially blocked
	if (xSemaphoreTake(devPtr->binSemaphore,0) != pdTRUE) {
		// free up everyone and go home
		vQueueDelete(devPtr->binSemaphore);
		return(UARTErrInit);
	}
		// Allocate the two queues to be used to communicate with other tasks
	if ((devPtr->inQ = xQueueCreate(UARTQLen,sizeof(UARTMsg))) == NULL) {
		// free up everyone and go home
		vQueueDelete(devPtr->binSemaphore);
		return(UARTErrInit);
	}
	if ((devPtr->outQ = xQueueCreate(UARTQLen,sizeof(UARTMsg))) == NULL) {
		// free up everyone and go home
		vQueueDelete(devPtr->binSemaphore);
		vQueueDelete(devPtr->outQ);
		return(UARTErrInit);
	}

	char taskLabel[8];
	sprintf(taskLabel,"UART%d",devPtr->devNum);
	if ((retval = xTaskCreate( vUARTMonitorTask, (signed char*) taskLabel, uartSTACK_SIZE,(void *) devPtr, devPtr->taskPriority, ( xTaskHandle * ) NULL )) != pdPASS) {
		VT_HANDLE_FATAL_ERROR(retval);
		return(UARTErrInit); // return is just to keep the compiler happy, we will never get here
	} else {
		return UARTInitSuccess;
	}

}


portBASE_TYPE UARTEnQ(UARTStruct *dev,uint8_t msgType,uint8_t slvAddr,uint8_t txLen,const uint8_t *txBuf,uint8_t rxLen)
{
	UARTMsg msgBuf;
	int i;

    msgBuf.slvAddr = slvAddr;
	msgBuf.msgType = msgType;
	msgBuf.rxLen = rxLen;
	if (msgBuf.rxLen > UARTMLen) {
		VT_HANDLE_FATAL_ERROR(0);
	}
	msgBuf.txLen = txLen;
	if (msgBuf.txLen > UARTMLen) {
		VT_HANDLE_FATAL_ERROR(0);
	}
	for (i=0;i<msgBuf.txLen;i++) {
		msgBuf.buf[i] = txBuf[i];
	}
	return(xQueueSend(dev->inQ,(void *) (&msgBuf),portMAX_DELAY));

}

void UART1_IntHandler(void)
{	
	LPC_UART_TypeDef* uartDevice = uart1static->devAddr;
	uint8_t intType = UART_GetIntId(uartDevice);
	UART_IntConfig(uartDevice, UART_INTCFG_RBR, DISABLE);
	if(intType == UART_INTCFG_RBR);
	{
			uint8_t data = UART_ReceiveByte(uartDevice);
			uart1static->recvBuf[uart1static->recvCount] = data;
			uart1static->recvCount++;
			uint8_t* recbuf = uart1static->recvBuf;
			if(uart1static->recvCount>=UARTMLen && recbuf[0]==0xD1)
			{
				 //UARTEnQ(uart1static,1,0,uart1static->recvCount,uart1static->recvBuf,0);
				 
				 sendSensorData(uart1static->recvBuf[1], uart1static->recvBuf[2], uart1static->recvBuf[3]);
				 uart1static->recvCount = 0;
			}
	}
	
	UART_IntConfig(uartDevice, UART_INTCFG_RBR, ENABLE);	
}

   /*
portBASE_TYPE UARTDeQ(UARTStruct *dev,uint8_t maxRxLen,uint8_t *rxBuf,uint8_t *rxLen,uint8_t *msgType,uint8_t *status)
{
	return 0;
}
 */

static portTASK_FUNCTION( vUARTMonitorTask, pvParameters )
{
	// Get the i2c structure for this task/device
	UARTStruct *devPtr = (UARTStruct *) pvParameters;
	UARTMsg msgBuffer;
	//uint8_t tmpRxBuf[UARTMLen];	 //Enable RX interrupt


	 UART_IntConfig(devPtr->devAddr, UART_INTCFG_RBR, ENABLE);
	 NVIC_EnableIRQ(UART1_IRQn);
	 
	   
	  
	for (;;) {

		if (xQueueReceive(devPtr->inQ,(void *) &msgBuffer,portMAX_DELAY) != pdTRUE) {
			VT_HANDLE_FATAL_ERROR(0);
		}
		//Log that we are processing a message
		//vtITMu8(vtITMUARTMsg,msgBuffer.msgType);

		/*
		int val = devPtr->devAddr->LSR;
		if ((val & UART_LSR_RDR)){
			uint8_t data = UART_ReceiveByte(devPtr->devAddr);
			UART_SendByte(devPtr->devAddr, data);
		}
		*/

		int i;
		if(msgBuffer.msgType==0)
		{
			for(i=0;i<msgBuffer.txLen;i++)
			{
				UART_SendByte(devPtr->devAddr, msgBuffer.buf[i]);
			}
		}

		else if(msgBuffer.msgType==1)
		{
			for(i=0;i<msgBuffer.txLen;i++)
			{
				UART_SendByte(devPtr->devAddr, msgBuffer.buf[i]);
			}
		}

		// Block until the I2C operation is complete -- we *cannot* overlap operations on the I2C bus...
		//if (xSemaphoreTake(devPtr->binSemaphore,portMAX_DELAY) != pdTRUE) {
			// something went wrong 
		//	VT_HANDLE_FATAL_ERROR(0);
		//}
	}	
}